package com.abpa.util.unidata.resources;

import com.abpa.util.unidata.*;
import java.io.*;
import java.util.logging.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.beans.BeansException;
import org.springframework.context.*;

/**
 * This resource provides access to an atom feed of a list of files in this account
 * @author Matthew Sowders
 */
@Path("{account}")
public class AccountResource implements ApplicationContextAware {
    private static final String USER_ROLE = "UNIDATA_REST_USER";
    // The unidata session to connect to
    private Session session;
    // The object used to build a command
    private CommandBuilder builder;
    // The name of the Session bean
    private String account;
    // The object used to pass the command and store the response
    private Command command;
    // The transformer used to convert to atom
    private Transformer transformer;
    @Context
    private UriInfo context;
    private ApplicationContext appContext;
    private CacheManager cacheManager;

    /**
     * This resource provides access to an atom feed of a list of files in this account
     * @param account The name of the Session bean for the session
     * @return a HTTP response
     */
    @GET
    @Produces("application/atom+xml")
    public Response getAtomFeed(
            @Context SecurityContext sc,
            @DefaultValue("")
            @PathParam("account") String account) {
        Logger.getLogger(AccountResource.class.getName()).log(Level.INFO, "GET request", context.getRequestUri().toString());
        Response response;
        Cache cache = cacheManager.getCache(getClass().getName());
        if(!sc.isUserInRole(USER_ROLE)){
            throw new WebApplicationException(Response.Status.FORBIDDEN);
        }
        if (account.equals("")) {
            return Response.noContent().build();
        }
        if (cache.isKeyInCache(context.getRequestUri())) {
            Element cachedResponse = cache.get(context.getRequestUri());
            if (cachedResponse != null && cachedResponse.getObjectValue() instanceof Response) {
                response = (Response) cachedResponse.getObjectValue();
            } else {
                response = Response.serverError().build();
                Logger.getLogger(AccountResource.class.getName()).log(Level.SEVERE, "The uri:" + context.getRequestUri().toString() + " exists in cache but the value is not an instance of response or it is null.");
            }
        } else {
            setSession(account);
            command = getBuilder().list("VOC").appendCondition("F1", "EQ", "F").sortBy("F1").toXmlElements().build();
            command.execute(getSession());
            try {
                response = Response.ok(buildAtomFeed()).build();
                cache.put(new Element(context.getRequestUri(),response));
            } catch (TransformerConfigurationException ex) {
                Logger.getLogger(AccountResource.class.getName()).log(Level.SEVERE, null, ex);
                // if there was an error in transformation, then the
                // document returned by the query was empty or malformed
                response = Response.noContent().build();
            } catch (TransformerException ex) {
                Logger.getLogger(AccountResource.class.getName()).log(Level.SEVERE, null, ex);
                // if there was an error in transformation, then the
                // document returned by the query was empty or malformed
                response = Response.noContent().build();
            }
        }
        return response;
    }

    /**
     * Build an atom feed out of the response from unidata
     * @return an atom document
     */
    private String buildAtomFeed()
            throws TransformerConfigurationException,
            TransformerException {
        StringReader source = new StringReader(command.getResponse());
        StringWriter feed = new StringWriter();

        getTransformer().setParameter("title", account);
        getTransformer().setParameter("resourceuri",
                getContext().getAbsolutePathBuilder().path("file").build(account).toString());

        getTransformer().transform(new StreamSource(source), new StreamResult(feed));
        return feed.toString();
    }

    /**
     * @return the session
     */
    public Session getSession() {
        return session;
    }

    /**
     * @param account The name of the Session bean
     */
    public void setSession(String account) {
        session = (Session) appContext.getBean(account);
        this.account = account;
    }

    /**
     * @return the context
     */
    public UriInfo getContext() {
        return context;
    }

    /**
     * @param context the context to set
     */
    public void setContext(UriInfo context) {
        this.context = context;
    }

    /**
     * Sets the applicationContext. This is needed to get the Session bean.
     * @param appContext
     * @throws BeansException
     */
    public void setApplicationContext(ApplicationContext appContext) throws BeansException {
        this.appContext = appContext;
    }

    /**
     * @return the transformer
     */
    public Transformer getTransformer() {
        return transformer;
    }

    /**
     * @param transformer the transformer to set
     */
    public void setTransformer(Transformer transformer) {
        this.transformer = transformer;
    }

    /**
     * @return the builder
     */
    public CommandBuilder getBuilder() {
        return builder;
    }

    /**
     * @param builder the builder to set
     */
    public void setBuilder(CommandBuilder builder) {
        this.builder = builder;
    }

    /**
     * @return the cacheManager
     */
    public CacheManager getCacheManager() {
        return cacheManager;
    }

    /**
     * @param cacheManager the cacheManager to set
     */
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
}
